I switched from PHP 7.2.26 to PHP 7.3.13 and that broke my WordPress blog. The problem was Aram Kocharyan’s Crayon Syntax Highlighter plugin. Version 2.8.4 has not been updated for 4 years.
PCRE to PCRE2
The transition from PHP 7.2.x to PHP 7.3.x upgraded the PCRE (Perl Compatible Regular Expressions) extension to PCRE2. User ‘baseapp’ identified the problem was in function clean_id of class CrayonLang:
| 
					 1 2 3 4 5 6 7  | 
						// Override function clean_id($id) {   $id = CrayonUtil::space_to_hyphen( strtolower(trim($id)) );   // Was: return preg_replace('/[^\w-+#]/msi', '', $id);   // See: https://wordpress.org/support/topic/plugin-breaks-with-php-7-3/   return preg_replace("/[^\w\-+#]/msi", '', $id); }  | 
					
The preg_replace function performs a regular expression search and replace. The fix changes the pattern from /[^\w-+#]/msi to /[^\w\-+#]/msi. In particular, the character class changes from the negation (^) of \w-+# to the negation of \w\-+#. The hyphen (-) is now escaped (\-); otherwise it would be interpreted as a metacharacter indicating a character range.
I identified a similar problem with a line of the YAML language definition:
| 
					 1 2  | 
						#   LIST_KEY:STRING     ((\-\s*)?[\w-\\]+(?=\s*:))|(\-\s*(?=\{))     LIST_KEY:STRING     ((\-\s*)?[\w\-\\]+(?=\s*:))|(\-\s*(?=\{))  | 
					
preg_quote
From PHP 7.3.0, the # character is quoted by function preg_quote. That affects the logic of the lines function of the CrayonUtil class:
| 
					 1 2 3 4 5 6 7 8 9  | 
						if ($escape_regex) {   for ($i = 0; $i < count($lines); $i++) {     $lines[$i] = self::esc_regex($lines[$i]);     // Was: Before PHP 7.3.0: If we have used \#, then we don't want it to become \\#     // Was: $lines[$i] = preg_replace('|\\\\\\\\#|', '\#', $lines[$i]);     // From PHP 7.3.0: If we have used \#, then we don't want it to become \\\#     $lines[$i] = preg_replace('|\\\\\\\\\\\\#|', '\#', $lines[$i]);   } }  | 
					
CrayonParser::validate_regex
In order to identify problems with invalid regular expressions, I extended part of the CrayonParser::validate_regex function:
| 
					 1 2 3 4 5 6  | 
						// Test if regex is valid if (@preg_match("#$regex#", '') === FALSE) {   // Was: CrayonLog::syslog("The regex for the element '{$element->name()}' in '{$element->path()}' is not valid.");   CrayonLog::syslog("The regex '{$regex}' for the element '{$element->name()}' in '{$element->path()}' is not valid.");   return FALSE; }  |